﻿using System;
using System.Collections.Generic;
using System.Linq;
using Caliburn.Micro;
using DomusDotNet.Sbm.Client.WP7.Services;
using DomusDotNet.Sbm.Client.WP7.Models;
using DomusDotNet.Sbm.Client.WP7.Framework;
using System.Reflection;
using System.Runtime.Serialization;


namespace DomusDotNet.Sbm.Client.WP7.ViewModels
{
    public class BookCriteriaSetPageViewModel : Conductor<BookListViewModel>.Collection.OneActive, IHasBusyState
    {
        Func<BookListViewModel> factory;
        public BookCriteriaSetPageViewModel(Func<BookListViewModel> factory)
        {
            this.factory = factory;
			this.BusyState = new BusyState();
        }


        public string Set { get; set; }

		
        protected override void OnInitialize()
        {
			if (ListDefinitions != null)
			{
				AddListDefinitions();
				return;
			}
			
			if (string.IsNullOrEmpty(Set)) return;

            var func = this.GetType().GetMethod("Initialize" + Set, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic);
            if (func == null) throw new ArgumentOutOfRangeException("Set", "Invalid set specified");

            var coroutine = (IEnumerable<IResult>)func.Invoke(this, new object[] { });

            Coroutine.BeginExecute(coroutine.GetEnumerator());
        }


        IEnumerable<IResult> InitializeByCategory()
        {
			using (BusyState.Set("loading categories..."))
			{
				DisplayName = "by category";

				var result = new AllCategoriesQuery().AsResult();
				yield return result;


				ListDefinitions = result.Response
					.Select(category => new ListDefinition { 
						DisplayName = category ,
						Query = new BooksByCategoryQuery { Category = category }
					})
					.ToArray();
				
				AddListDefinitions();
			}
        }

        IEnumerable<IResult> InitializeByStatus()
        {
			using (BusyState.Set("loading statuses..."))
			{
				DisplayName = "by status";


				ListDefinitions = LendStatus.All
					.Select(status => new ListDefinition
					{
						DisplayName = status.DisplayName,
						Query = new BooksByLendStatusQuery { Status = status }
					})
					.ToArray();

				AddListDefinitions();
				yield break;
			}
        }


		public ListDefinition[] ListDefinitions { get; set; }


		public void AddListDefinitions() { 
			foreach (var def in ListDefinitions) {

				AddList<IEnumerable<BookViewModel>>(def.DisplayName, (IQuery<IEnumerable<BookViewModel>>)def.Query);
			}
		}
        public void AddList<TResponse>(string title, IQuery<TResponse> query) where TResponse : IEnumerable<BookViewModel>
        {

            var child = factory.Invoke();
            child.Setup(title, query);

            if (this.Items.Any())
                this.Items.Add(child);
            else
                this.ActivateItem(child);
        }

		public BusyState BusyState {get; private set ;}

		[DataContract]
		[KnownType(typeof(BooksByCategoryQuery))]
		[KnownType(typeof(BooksByLendStatusQuery))]
		public class ListDefinition {
			[DataMember]
			public string DisplayName { get; set; }
			[DataMember]
			
			public object Query { get; set; }
		}
	}
}
